package com.imageflowpro.image_flow_pro.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.imageflowpro.image_flow_pro.constant.JwtClaimsConstant;
import com.imageflowpro.image_flow_pro.context.BaseContext;
import com.imageflowpro.image_flow_pro.dto.VerificationCodeDTO;
import com.imageflowpro.image_flow_pro.exception.BaseException;
import com.imageflowpro.image_flow_pro.po.MediaImage;
import com.imageflowpro.image_flow_pro.po.User;
import com.imageflowpro.image_flow_pro.po.VerificationCode;
import com.imageflowpro.image_flow_pro.mapper.VerificationCodeMapper;
import com.imageflowpro.image_flow_pro.service.IVerificationCodeService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.imageflowpro.image_flow_pro.vo.UserUploadImageVO;
import com.imageflowpro.image_flow_pro.vo.VerificationCodeVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.security.SecureRandom;
import java.time.LocalDateTime;
import java.util.*;

/**
 * <p>
 * 验证码表 服务实现类
 * </p>
 *
 * @author 张家浩
 * @since 2025-05-07
 */
@Service
public class VerificationCodeServiceImpl extends ServiceImpl<VerificationCodeMapper, VerificationCode> implements IVerificationCodeService {

    public static final String ACTIVATION_CODE_NAME="ACTIVATION";
    public static final String SUBMIT_ORDER_CODE_NAME="SUBMIT_ORDER";
    public static final String SUPER_SUBMIT_ORDER_CODE_NAME="SUPER_SUBMIT_ORDER";

    // 可选字符集：数字 + 大写 + 小写字母
    private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    private static final int CODE_LENGTH = 8;

    private static final SecureRandom random = new SecureRandom();

    public static String generateCode() {
        StringBuilder sb = new StringBuilder(CODE_LENGTH);
        for (int i = 0; i < CODE_LENGTH; i++) {
            int index = random.nextInt(CHARACTERS.length());
            sb.append(CHARACTERS.charAt(index));
        }
        return sb.toString();
    }

    @Autowired
    private VerificationCodeMapper verificationCodeMapper;


    @Override
    @Transactional
    public VerificationCodeVO userImageUploadVerification(String code) {
        if(code==null){
            throw new BaseException("请传入验证码");
        }
        List<VerificationCode> verificationCodeList = this.lambdaQuery()
                .eq(VerificationCode::getCode, code)
                .and(wrapper -> wrapper
                        .eq(VerificationCode::getType, VerificationCodeServiceImpl.SUPER_SUBMIT_ORDER_CODE_NAME)
                        .or()
                        .eq(VerificationCode::getType, VerificationCodeServiceImpl.SUBMIT_ORDER_CODE_NAME)
                )
                .orderByDesc(VerificationCode::getExpireAt)
                .list();
        if(verificationCodeList.isEmpty()){
            throw new BaseException("验证码不存在");
        }
        VerificationCode verificationCode = verificationCodeList.get(0);
        if(!LocalDateTime.now().isBefore(verificationCode.getExpireAt())){
            throw new BaseException("验证码已经过期了");
        }
        if(verificationCodeList.size()>=2&& LocalDateTime.now().isBefore(verificationCodeList.get(1).getCreatedAt())) {
            verificationCodeMapper.delete(new LambdaQueryWrapper<VerificationCode>()
                    .eq(VerificationCode::getCode, code)
                    .and(wrapper -> wrapper
                            .eq(VerificationCode::getType, VerificationCodeServiceImpl.SUPER_SUBMIT_ORDER_CODE_NAME)
                            .or()
                            .eq(VerificationCode::getType, VerificationCodeServiceImpl.SUBMIT_ORDER_CODE_NAME)
                    )
            );
            throw new BaseException("出现了两个相同内容和类别，而且都没有过期的验证码，已经全部清除，请重新获取验证码");
        }
        if(!(BaseContext.getCurrentId().equals(verificationCode.getUserId())||verificationCode.getUserId()==null)){
            throw new BaseException("此验证码已经被别人使用了");
        }
        if (verificationCode.getUserId()==null) {
            verificationCode.setUserId(BaseContext.getCurrentId());
            this.updateById(verificationCode);
        }
        VerificationCodeVO verificationCodeVO = new VerificationCodeVO();
        verificationCodeVO.setId(verificationCodeList.get(0).getId());
        verificationCodeVO.setExpireAt(verificationCodeList.get(0).getExpireAt());
        //查询上传为完成的图片
        List<MediaImage> list = Db.lambdaQuery(MediaImage.class)
                .eq(MediaImage::getVerificationId, verificationCodeVO.getId())
                .eq(MediaImage::getUploadBy, BaseContext.getCurrentId())
                .list();
        ArrayList<UserUploadImageVO> imageList = new ArrayList<>();
        list.forEach(mediaImage -> {
            UserUploadImageVO userUploadImageVO = new UserUploadImageVO();
            userUploadImageVO.setMinioName(mediaImage.getMinioName());
            userUploadImageVO.setId(mediaImage.getId());
            imageList.add(userUploadImageVO);
        });
        verificationCodeVO.setImageList(imageList);
        return verificationCodeVO;
    }

    @Override
    public List<VerificationCodeDTO> adminGetVerificationCodeList() {
        User loginUser = Db.lambdaQuery(User.class)
                .eq(User::getId, BaseContext.getCurrentId())
                .one();
        List<VerificationCode> verificationCodeList;
        if(loginUser.getRole().equals(JwtClaimsConstant.SUPER_ADMIN_ROLE)){
            verificationCodeList = this.list();
        }
        else {
            verificationCodeList=this.lambdaQuery()
                    .ne(VerificationCode::getType,VerificationCodeServiceImpl.ACTIVATION_CODE_NAME)
                    .list();
        }
        List<VerificationCodeDTO> verificationCodeDTOS=new ArrayList<>();
        List<User> userList = Db.lambdaQuery(User.class)
                .eq(User::getRole, JwtClaimsConstant.USER_ROLE)
                .list();
        Map<Long,User> userMap=new HashMap<>();
        userList.forEach(user -> userMap.put(user.getId(),user));
        verificationCodeList.forEach(verificationCode -> {
            VerificationCodeDTO verificationCodeDTO = new VerificationCodeDTO();
            BeanUtil.copyProperties(verificationCode,verificationCodeDTO);
            String nickname="无";
            if(verificationCode.getUserId()!=null) {
                nickname = userMap.get(verificationCode.getUserId()).getNickname();
            }
            verificationCodeDTO.setUserName(nickname);
            verificationCodeDTOS.add(verificationCodeDTO);
        });
        return verificationCodeDTOS;
    }

    @Override
    public void adminCreateCode(String type) {
        if(type.equals(VerificationCodeServiceImpl.ACTIVATION_CODE_NAME)){
            boolean exists = Db.lambdaQuery(User.class)
                    .eq(User::getId, BaseContext.getCurrentId())
                    .eq(User::getRole, JwtClaimsConstant.SUPER_ADMIN_ROLE)
                    .exists();
            if(!exists){
                throw new BaseException("只有超级管理员可以创建账号激活码");
            }
        }

        String code = generateCode();
        while (this.lambdaQuery()
                .eq(VerificationCode::getCode,code)
                .exists()){
            code = generateCode();
        }
        VerificationCode verificationCode = new VerificationCode();
        verificationCode.setCode(code);
        verificationCode.setType(type);
        LocalDateTime now = LocalDateTime.now()
                .withSecond(0)
                .withNano(0);
       verificationCode.setCreatedAt(LocalDateTime.now());
       if(type.equals(VerificationCodeServiceImpl.ACTIVATION_CODE_NAME)){
           verificationCode.setExpireAt(now.plusMinutes(15));
       }
       else {
           verificationCode.setExpireAt(now.plusHours(1));
       }
       this.save(verificationCode);
    }

    @Override
    public void adminDeleteVerificationCodeById(Long codeId) {
        boolean exists = this.lambdaQuery()
                .eq(VerificationCode::getId, codeId)
                .exists();
        if(exists){
            this.removeById(codeId);
        }
    }
}
